package com.peanut.model;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;

import org.apache.commons.lang.BooleanUtils;
import org.springframework.security.core.CredentialsContainer;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.GrantedAuthorityImpl;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.util.Assert;

import com.peanut.persistence.RoleMapper;

public class User implements UserDetails, CredentialsContainer {
	private static final long serialVersionUID = 4201376985591398272L;

	private String password;
    private String username;
    private Set<GrantedAuthority> authorities;
    private boolean accountNonExpired;
    private boolean accountNonLocked;
    private boolean credentialsNonExpired;
    private boolean enabled;
	
	private String companyCode;
	private String companyName;
	private String userCode;
	private String flag;
	private Integer version;
	private String userType;
	
	private List<Role> roles;
	
	public User(String userCode, String password, boolean enabled, boolean accountNonExpired,
            boolean credentialsNonExpired, boolean accountNonLocked, Collection<? extends GrantedAuthority> authorities) {

        if (((userCode == null) || "".equals(userCode)) || (password == null)) {
            throw new IllegalArgumentException("Cannot pass null or empty values to constructor");
        }

        this.userCode = userCode;
        this.password = password;
        this.enabled = enabled;
        this.accountNonExpired = accountNonExpired;
        this.credentialsNonExpired = credentialsNonExpired;
        this.accountNonLocked = accountNonLocked;
        this.authorities = Collections.unmodifiableSet(sortAuthorities(authorities));
    }
	
	public List<Role> getRoles() {
		return roles;
	}
	public void setRoles(List<Role> roles) {
		this.roles = roles;
	}
	public String getCompanyCode() {
		return companyCode;
	}
	public void setCompanyCode(String companyCode) {
		this.companyCode = companyCode;
	}
	public String getCompanyName() {
		return companyName;
	}
	public void setCompanyName(String companyName) {
		this.companyName = companyName;
	}
	public String getUserCode() {
		return userCode;
	}
	public void setUserCode(String userCode) {
		this.userCode = userCode;
	}
	public String getFlag() {
		return flag;
	}
	public void setFlag(String flag) {
		this.flag = flag;
	}
	public Integer getVersion() {
		return version;
	}
	public void setVersion(Integer version) {
		this.version = version;
	}
	public String getUserType() {
		return userType;
	}
	public void setUserType(String type) {
		this.userType = type;
	}
	
	public void setPassword(String password) {
		this.password = password;
	}

	public void setUsername(String username) {
		this.username = username;
	}
	
	public String getUsername2() {
        return this.username;
    }

	public void setAuthorities(Set<GrantedAuthority> authorities) {
		this.authorities = authorities;
	}
	
	public User map2Model(HashMap<String, String> userMap, RoleMapper roleMapper) {
		com.peanut.model.User user = null;
		if (userMap != null) {
			Collection<GrantedAuthority> auths = new ArrayList<GrantedAuthority>();
			List<Role> roleList = roleMapper.queryRolesByAccount(userMap.get("usercode").toString());
			if (roleList != null) {
				for (Role role : roleList) {
					GrantedAuthorityImpl auth = new GrantedAuthorityImpl(role.getName());
					auths.add(auth);
				}
			}
			user = new com.peanut.model.User(userMap.get("usercode").trim(), userMap.get("password").trim(), 
					BooleanUtils.toBoolean(Integer.parseInt(String.valueOf(userMap.get("enabled")))), 
					BooleanUtils.toBoolean(Integer.parseInt(String.valueOf(userMap.get("accountnonexpired")))), 
					BooleanUtils.toBoolean(Integer.parseInt(String.valueOf(userMap.get("credentialsnonexpired")))), 
					BooleanUtils.toBoolean(Integer.parseInt(String.valueOf(userMap.get("accountnonlocked")))), 
					auths);
			user.setUsername(userMap.get("username").trim());
			user.setCompanyCode(userMap.get("comcode").trim());
			user.setCompanyName(userMap.get("comcname").trim());
			user.setFlag(userMap.get("flag").trim());
			user.setVersion(Integer.parseInt(String.valueOf(userMap.get("version"))));
			user.setUserType(userMap.get("user_type"));
			user.setRoles(roleList);
		}
		return user;
	}

	//~ Methods ========================================================================================================

    public Collection<GrantedAuthority> getAuthorities() {
        return authorities;
    }

    public String getPassword() {
        return password;
    }

    //专为spring security的号
    public String getUsername() {
        return userCode;
    }

    public boolean isEnabled() {
        return enabled;
    }

    public boolean isAccountNonExpired() {
        return accountNonExpired;
    }

    public boolean isAccountNonLocked() {
        return accountNonLocked;
    }

    public boolean isCredentialsNonExpired() {
        return credentialsNonExpired;
    }

    public void eraseCredentials() {
        password = null;
    }
	
	private static SortedSet<GrantedAuthority> sortAuthorities(Collection<? extends GrantedAuthority> authorities) {
        Assert.notNull(authorities, "Cannot pass a null GrantedAuthority collection");
        // Ensure array iteration order is predictable (as per UserDetails.getAuthorities() contract and SEC-717)
        SortedSet<GrantedAuthority> sortedAuthorities =
            new TreeSet<GrantedAuthority>(new AuthorityComparator());

        for (GrantedAuthority grantedAuthority : authorities) {
            Assert.notNull(grantedAuthority, "GrantedAuthority list cannot contain any null elements");
            sortedAuthorities.add(grantedAuthority);
        }

        return sortedAuthorities;
    }
	
	private static class AuthorityComparator implements Comparator<GrantedAuthority>, Serializable {
		private static final long serialVersionUID = 5464932001740658770L;

		public int compare(GrantedAuthority g1, GrantedAuthority g2) {
            // Neither should ever be null as each entry is checked before adding it to the set.
            // If the authority is null, it is a custom authority and should precede others.
            if (g2.getAuthority() == null) {
                return -1;
            }

            if (g1.getAuthority() == null) {
                return 1;
            }

            return g1.getAuthority().compareTo(g2.getAuthority());
        }
    }
}
